package main

import (
	"bytes"
	"compress/gzip"
	"crypto/md5"
	"crypto/rand"
	"encoding/base64"
	"encoding/binary"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io"
	"math"
	"net/url"
	"reflect"
	"regexp"
	"sort"
	"strconv"
	"strings"
	"time"
)

type Int64Slice []int64

func (this Int64Slice) Len() int             { return len(this) }
func (this Int64Slice) Swap(i, j int64)      { this[i], this[j] = this[j], this[i] }
func (this Int64Slice) Less(i, j int64) bool { return this[i] < this[j] }
func Inttime2String(data int64) string {
	tm := time.Unix(data, 0)
	s_tm := tm.Format("2006-01-02 15:04:05")
	return s_tm
}

// 生成32位md5字串
func GetMd5String(s string) string {
	h := md5.New()
	h.Write([]byte(s))
	return hex.EncodeToString(h.Sum(nil))
}

// 生成Guid字串
func UniqueId() string {
	b := make([]byte, 48)

	if _, err := io.ReadFull(rand.Reader, b); err != nil {
		return ""
	}
	return GetMd5String(base64.URLEncoding.EncodeToString(b))
}

func Daoxu(a Int64Slice) Int64Slice {
	sort.Slice(a, func(i, j int) bool { return a[i] > a[j] })

	return a
}

func Zhengxu(a Int64Slice) Int64Slice {
	sort.Slice(a, func(i, j int) bool { return a[i] < a[j] })

	return a
}
func Strtime2Int64(datetime string) int64 {

	tm2, _ := time.Parse("2006-01-02 15:04:05", datetime)
	//fmt.Println(tm2.Unix())
	return tm2.Unix() - 8*3600
	////日期转化为时间戳
	//timeLayout := "2006-01-02 15:04:05"  //转化所需模板
	////
	////tm2, _ := time.Parse(timeLayout, "2014-06-15 08:37:18")
	//////fmt.Println(tm2.Unix())
	////return tm2.Unix()-8*3600
	//loc, _ := time.LoadLocation("Local") //获取时区
	//tmp, _ := time.ParseInLocation(timeLayout, datetime, loc)
	//timestamp := tmp.Unix() //转化为时间戳 类型是int64
	//return timestamp
}

func Strtime2Float64(datetime string) float64 {
	//日期转化为时间戳
	timeLayout := "2006-01-02 15:04:05"  //转化所需模板
	loc, _ := time.LoadLocation("Local") //获取时区
	tmp, _ := time.ParseInLocation(timeLayout, datetime, loc)
	timestamp := tmp.Unix() //转化为时间戳 类型是int64
	return float64(timestamp)
}
func Interface2Int64(inte interface{}) int64 {

	switch reflect.TypeOf(inte).Kind() {
	case reflect.Int:
		return int64(inte.(int))
	case reflect.Int64:
		return inte.(int64)
	case reflect.Int8:
		return int64(inte.(int))
	case reflect.Float64:
		return int64(inte.(float64))
	case reflect.Float32:
		return int64(inte.(float32))
	}
	return 0
}
func GMT() string {
	//输出theTime 2015-01-01 15:15:00 +0800 CST
	toBeCharge := "2015-01-01 00:00:00"                             //待转化为时间戳的字符串 注意 这里的小时和分钟还要秒必须写 因为是跟着模板走的 修改模板的话也可以不写
	timeLayout := "2006-01-02 15:04:05"                             //转化所需模板
	loc, _ := time.LoadLocation("Local")                            //重要：获取时区
	theTime, _ := time.ParseInLocation(timeLayout, toBeCharge, loc) //使用模板在对应时区转化为time.time类型

	return theTime.String()
}
func Str2Int(str string) int {
	val, _ := strconv.ParseInt(str, 10, 32)
	return int(val)
}
func Str2Int64(str string) int64 {
	val, _ := strconv.ParseInt(str, 10, 64)
	return val
}
func Interface2Float64(inte interface{}) float64 {
	switch reflect.TypeOf(inte).String() {
	case "int":
		return float64(inte.(int))
	case "int64":
		return float64(inte.(int64))
	case "int8":
		return float64(inte.(int))
	case "float32":
		return float64(inte.(float32))
	case "float64":
		return inte.(float64)
	case "float":
		return inte.(float64)
	default:
		return float64(len(Strval(inte)))
	}

	return 0
}

func Log(a ...interface{}) {
	dd := make([]interface{}, 0)
	dd = append(dd, Strtime())
	for _, k := range a {
		dd = append(dd, k)
	}
	fmt.Println(dd...)
}
func Strtime() string {
	return time.Now().Format("2006-01-02 15:04:05")
}
func StrtimeM() string {
	return time.Now().Format("2006-01-02 15:04:05.000")
}
func InterfaceSlice2StringSlice(data interface{}) []string {
	if reflect.TypeOf(data).String() == "[]interface {}" {
		dd := make([]string, 0)
		for _, item := range data.([]interface{}) {
			dd = append(dd, item.(string))
		}
		return dd
	} else {
		return data.([]string)
	}
}
func InterfaceSlice2MapSlice(data interface{}) []map[string]interface{} {
	if reflect.TypeOf(data).String() == "[]interface {}" {
		dd := make([]map[string]interface{}, 0)
		for _, item := range data.([]interface{}) {
			dd = append(dd, item.(map[string]interface{}))
		}
		return dd
	} else {
		return data.([]map[string]interface{})
	}
}

func RemoveFromSlice(datas []int64, data int64) []int64 {

	new_data := datas

	cur_index := -1
	for index, v := range datas {
		if v == data {
			cur_index = index
		}
	}
	if cur_index > -1 {
		new_data = append(new_data[:cur_index], new_data[cur_index+1:]...)
	}
	return new_data
}
func BytesToFloat32(bys []byte) float32 {
	bits := binary.BigEndian.Uint32(bys)

	return math.Float32frombits(bits)
}
func BytesToFloat64(bys []byte) float64 {
	bits := binary.BigEndian.Uint64(bys)

	return math.Float64frombits(bits)
}

func BytesToInt64(bys []byte) int64 {
	bin_buf := bytes.NewBuffer(bys)
	var x int64
	binary.Read(bin_buf, binary.BigEndian, &x)
	return x
}
func BytesToInt(bys []byte) int32 {
	bin_buf := bytes.NewBuffer(bys)
	var x int32
	binary.Read(bin_buf, binary.BigEndian, &x)
	return x
}
func BytesToIntLittle(bys []byte) int32 {
	bytebuff := bytes.NewBuffer(bys)
	var data int32
	binary.Read(bytebuff, binary.LittleEndian, &data)
	return int32(data)
}
func Slice2Map(data interface{}) []map[string]interface{} {
	kk := make([]map[string]interface{}, 0)
	for _, item := range data.([]interface{}) {
		kk = append(kk, item.(map[string]interface{}))
	}
	return kk
}
func ZhToUnicode(raw string) (string, error) {
	str, err := strconv.Unquote(strings.Replace(strconv.Quote(raw), `\\u`, `\u`, -1))
	if err != nil {
		return "", err
	}
	return str, nil
}
func SliceInterface2JSON(map0 []interface{}) string {
	dataType, _ := json.Marshal(map0)
	dataString, _ := url.QueryUnescape(string(dataType))
	dataStrings, _ := ZhToUnicode(dataString)

	return dataStrings
}
func Slice2JSON(map0 []map[string]interface{}) string {
	dataType, _ := json.Marshal(map0)
	dataString, _ := url.QueryUnescape(string(dataType))
	dataStrings, _ := ZhToUnicode(dataString)

	return dataStrings
}
func Map2JSON(map0 map[string]interface{}) string {
	dataType, _ := json.Marshal(map0)
	dataString, _ := url.QueryUnescape(string(dataType))
	dataStrings, _ := ZhToUnicode(dataString)

	return dataStrings
}
func CheckMap(mapdata map[string]interface{}, key string) bool {
	_, f := mapdata[key]
	return f
}
func GetStringMd5(s string) string {
	md5 := md5.New()
	md5.Write([]byte(s))
	md5Str := hex.EncodeToString(md5.Sum(nil))
	return md5Str
}
func CheckMapType(mapdata map[string]interface{}, key string, valuetype string) bool {
	_, f := mapdata[key]
	if !f {
		return false
	}
	if reflect.TypeOf(mapdata[key]).String() == valuetype {

		return true
	}
	return false
}

func RegReplace(allstr string, regstr string, newstr string) string {
	re3, _ := regexp.Compile(regstr)
	rep := re3.ReplaceAllString(allstr, newstr)
	return rep
}
func Arr2JSON(map0 []map[string]interface{}) string {
	dataType, _ := json.Marshal(map0)
	dataString := string(dataType)
	dataStrings, _ := ZhToUnicode(dataString)

	return dataStrings
}
func JSON2SliceStr(str string) []string {
	var tempMap []string
	err := json.Unmarshal([]byte(str), &tempMap)
	if err != nil {

	}
	return tempMap
}
func JSON2Slice(str string) []map[string]interface{} {
	var tempMap []map[string]interface{}
	err := json.Unmarshal([]byte(str), &tempMap)
	if err != nil {

	}
	return tempMap
}
func Map2MapSlice(str map[string]interface{}) map[string][]map[string]interface{} {
	var tempMap map[string][]map[string]interface{}
	for key, vv := range str {
		_, ok1 := tempMap[key]
		if !ok1 {
			tempMap[key] = make([]map[string]interface{}, 0)
		}
		if reflect.TypeOf(vv).String() == "[]interface {}" {
			for _, vvv := range vv.([]interface{}) {
				tempMap[key] = append(tempMap[key], vvv.(map[string]interface{}))
			}
		} else {
			tempMap[key] = vv.([]map[string]interface{})
		}
	}

	return tempMap
}
func JSON2MapSlice(str string) map[string][]map[string]interface{} {
	var tempMap map[string][]map[string]interface{}
	err := json.Unmarshal([]byte(str), &tempMap)
	if err != nil {

	}
	return tempMap
}
func JSON2Map(str string) map[string]interface{} {
	var tempMap map[string]interface{}
	err := json.Unmarshal([]byte(str), &tempMap)
	if err != nil {

	}
	return tempMap
}

func RegFindAll(str []byte, reg string) []string {
	re2, _ := regexp.Compile(reg)
	all := re2.FindAllSubmatch(str, -1)

	ddd := make([]string, 0)
	if len(all) > 0 {
		for _, v := range all {
			for _, vv := range v {
				ddd = append(ddd, string(vv))
			}

		}
	}
	return ddd
}

func BytesCombine(pBytes ...[]byte) []byte {
	return bytes.Join(pBytes, []byte(""))
}
func PackMap(data map[string]interface{}) []byte {
	str := Map2JSON(data)
	return PackBytes(GzipStr(str, 1))
}
func PackBytes(buf []byte) []byte {

	var len_b int32
	len_b = int32(len(buf))
	bytesBuffer := bytes.NewBuffer([]byte{})
	binary.Write(bytesBuffer, binary.LittleEndian, &len_b)
	d := bytesBuffer.Bytes()
	return BytesCombine(d, buf)
}

/*
interface 转字符串

	主要用来转换map中的空接口
*/
func Strval(value interface{}) string {
	var key string
	if value == nil {
		return key
	}
	switch value.(type) {
	case float64:
		ft := value.(float64)
		key = strconv.FormatFloat(ft, 'f', -1, 64)
	case float32:
		ft := value.(float32)
		key = strconv.FormatFloat(float64(ft), 'f', -1, 64)
	case int:
		it := value.(int)
		key = strconv.Itoa(it)
	case uint:
		it := value.(uint)
		key = strconv.Itoa(int(it))
	case int8:
		it := value.(int8)
		key = strconv.Itoa(int(it))
	case uint8:
		it := value.(uint8)
		key = strconv.Itoa(int(it))
	case int16:
		it := value.(int16)
		key = strconv.Itoa(int(it))
	case uint16:
		it := value.(uint16)
		key = strconv.Itoa(int(it))
	case int32:
		it := value.(int32)
		key = strconv.Itoa(int(it))
	case uint32:
		it := value.(uint32)
		key = strconv.Itoa(int(it))
	case int64:
		it := value.(int64)
		key = strconv.FormatInt(it, 10)
	case uint64:
		it := value.(uint64)
		key = strconv.FormatUint(it, 10)
	case string:
		key = value.(string)
	case []byte:
		key = string(value.([]byte))
	default:
		newValue, _ := json.Marshal(value)
		key = string(newValue)
	}

	return key
}

// 整形转换成字节
func IntToBytes(data int, kind byte) ([]byte, error) {
	switch kind {
	case 1:
		tmp := int8(data)
		bytesBuffer := bytes.NewBuffer([]byte{})
		binary.Write(bytesBuffer, binary.BigEndian, &tmp)
		return bytesBuffer.Bytes(), nil
	case 2:
		tmp := int16(data)
		bytesBuffer := bytes.NewBuffer([]byte{})
		binary.Write(bytesBuffer, binary.BigEndian, &tmp)
		return bytesBuffer.Bytes(), nil
	case 3, 4:
		tmp := int32(data)
		bytesBuffer := bytes.NewBuffer([]byte{})
		binary.Write(bytesBuffer, binary.BigEndian, &tmp)
		return bytesBuffer.Bytes(), nil
	}
	return nil, fmt.Errorf("IntToBytes b param is invaild")
}
func IntToBytesLittle(n int, b byte) ([]byte, error) {
	switch b {
	case 1:
		tmp := int8(n)
		bytesBuffer := bytes.NewBuffer([]byte{})
		binary.Write(bytesBuffer, binary.LittleEndian, &tmp)
		return bytesBuffer.Bytes(), nil
	case 2:
		tmp := int16(n)
		bytesBuffer := bytes.NewBuffer([]byte{})
		binary.Write(bytesBuffer, binary.LittleEndian, &tmp)
		return bytesBuffer.Bytes(), nil
	case 3, 4:
		tmp := int32(n)
		bytesBuffer := bytes.NewBuffer([]byte{})
		binary.Write(bytesBuffer, binary.LittleEndian, &tmp)
		return bytesBuffer.Bytes(), nil
	}
	return nil, fmt.Errorf("IntToBytes b param is invaild")
}

func Float32ToByte(float float32) []byte {
	bits := math.Float32bits(float)
	bytes := make([]byte, 4)
	binary.BigEndian.PutUint32(bytes, bits)
	return bytes
}
func ByteToFloat32Int64(bytes []byte) int64 {
	bits := binary.BigEndian.Uint32(bytes)
	return int64(math.Float32frombits(bits))
}
func ByteToFloat32(bytes []byte) float32 {
	bits := binary.BigEndian.Uint32(bytes)
	return math.Float32frombits(bits)
}
func Float64ToByte(float float64) []byte {
	bits := math.Float64bits(float)
	bytes := make([]byte, 8)
	binary.BigEndian.PutUint64(bytes, bits)
	return bytes
}

// 整形转换成字节
func Int32ToBytes(tmp int32) []byte {
	bytesBuffer := bytes.NewBuffer([]byte{})
	binary.Write(bytesBuffer, binary.BigEndian, &tmp)
	return bytesBuffer.Bytes()
}

// 整形转换成字节
func Int64ToBytes(tmp int64) []byte {
	bytesBuffer := bytes.NewBuffer([]byte{})
	binary.Write(bytesBuffer, binary.BigEndian, &tmp)
	return bytesBuffer.Bytes()
}

// 整形转换成字节
func Int64ToBytesLittle(tmp int64) []byte {
	bytesBuffer := bytes.NewBuffer([]byte{})
	binary.Write(bytesBuffer, binary.LittleEndian, &tmp)
	return bytesBuffer.Bytes()
}

func UngzipStr(str string) string {

	var out bytes.Buffer
	encoded, _ := base64.StdEncoding.DecodeString(str)
	ou1 := bytes.NewBuffer(encoded)
	r, e := gzip.NewReader(ou1)
	if e != nil {
		return str
	}
	io.Copy(&out, r)
	return out.String()
	//return b.Bytes()
}
func GzipStr(str string, level int) []byte {
	var b bytes.Buffer
	gz, _ := gzip.NewWriterLevel(&b, level)
	if _, err := gz.Write([]byte(str)); err != nil {
		panic(err)
	}
	if err := gz.Flush(); err != nil {
		panic(err)
	}
	if err := gz.Close(); err != nil {
		panic(err)
	}
	encoded := base64.StdEncoding.EncodeToString(b.Bytes())
	return []byte(encoded)
	//return b.Bytes()
}

func QueryUnescape(sv string) string {
	svv0, _ := url.PathUnescape(sv)
	svv, err00 := url.PathUnescape(svv0)
	if err00 != nil {
		return sv
	}
	return svv
}
func ParseUrlNoCheck(urlstr string) (status int, AllPath []string, UrlParams map[string]string, data map[string]string) {
	UrlParams = make(map[string]string)
	data = make(map[string]string)
	WenHao := false
	AllPath = make([]string, 0)
	status = 1

	PathStart := 0
	urlBytes := []byte(urlstr)

	ParamsValueIndex := -1
	ParamsKeyIndex := -1

	CurKey := ""
	CurValue := ""

	for i := 0; i < len(urlBytes); i++ {

		if urlBytes[i] == 47 && WenHao == false {
			if i > PathStart {
				sv := string(urlBytes[PathStart:i])
				svv := QueryUnescape(sv)
				AllPath = append(AllPath, svv)
			}
			PathStart = i + 1
		}
		if urlBytes[i] == 63 && WenHao == false {
			sv := string(urlBytes[PathStart:i])
			svv := QueryUnescape(sv)
			AllPath = append(AllPath, svv)

			WenHao = true
			PathStart = i + 1

			ParamsKeyIndex = i + 1
		}
		if WenHao == true {
			if urlBytes[i] == 61 && ParamsKeyIndex > -1 {

				sv := string(urlBytes[ParamsKeyIndex:i])

				CurKey = QueryUnescape(sv)
				ParamsKeyIndex = -1
				ParamsValueIndex = i + 1
			}
			if urlBytes[i] == 38 && ParamsValueIndex > -1 {
				sv := string(urlBytes[ParamsValueIndex:i])

				CurValue = QueryUnescape(sv)
				ParamsValueIndex = -1
				ParamsKeyIndex = i + 1
				UrlParams[CurKey] = CurValue

				if CurKey == "data" {
					json.Unmarshal([]byte(CurValue), &data)
				}

			}
		}
	}
	if WenHao == false {
		sv := string(urlBytes[PathStart:])
		svv := QueryUnescape(sv)
		AllPath = append(AllPath, svv)
	} else {
		if ParamsValueIndex >= 0 {
			sv := string(urlBytes[ParamsValueIndex:])

			CurValue = QueryUnescape(sv)
			UrlParams[CurKey] = CurValue

			if CurKey == "data" {
				json.Unmarshal([]byte(CurValue), &data)
			}
		}

	}

	status = 1

	return
}
func GzipStrNoBase64(str []byte) ([]byte, bool) {
	var b bytes.Buffer
	gz, _ := gzip.NewWriterLevel(&b, 1)
	if _, err := gz.Write(str); err != nil {
		fmt.Println("GzipStrNoBase64 Error1", err)
		return []byte(""), false
	}
	if err := gz.Flush(); err != nil {
		fmt.Println("GzipStrNoBase64 Error2", err)
		return []byte(""), false
	}
	if err := gz.Close(); err != nil {
		fmt.Println("GzipStrNoBase64 Error3", err)
		return []byte(""), false
	}
	//encoded := base64.StdEncoding.EncodeToString(b.Bytes())
	//return encoded, true
	return b.Bytes(), true

	//var in bytes.Buffer
	//w := gzip.NewWriter(&in)
	//w.Write(str)
	//w.Close()
	//return in.Bytes(), true
}
